gsk: Reuse VAOs with identical buffers
authorEmmanuele Bassi <ebassi@gnome.org>
Tue, 9 Aug 2016 10:24:05 +0000 (11:24 +0100)
committerEmmanuele Bassi <ebassi@gnome.org>
Tue, 18 Oct 2016 10:49:13 +0000 (11:49 +0100)
Just like we reuse texture ids with the same size we can, at the expense
of a little memory, reuse vertex buffers if they reference the same
attributes and contain the same data.

Each VAO is marked as free at the end of the frame, and if it's not
reused in the following frame, it gets dropped.

gsk/gskgldriver.c
gsk/gskgldriverprivate.h
gsk/gskglrenderer.c

index a6345259c75a58f46faf0d9c0d9aa2b4bb3e91b5..2f045cf7a91dfb69e1afc80a97a4b2bd3a634793 100644 (file)
@@ -22,6 +22,9 @@ typedef struct {
   GLuint buffer_id;
   GLuint position_id;
   GLuint uv_id;
+  GskQuadVertex *quads;
+  int n_quads;
+  gboolean in_use : 1;
 } Vao;
 
 typedef struct {
@@ -97,6 +100,7 @@ vao_free (gpointer data)
 {
   Vao *v = data;
 
+  g_free (v->quads);
   glDeleteBuffers (1, &v->buffer_id);
   glDeleteVertexArrays (1, &v->vao_id);
   g_slice_free (Vao, v);
@@ -238,14 +242,17 @@ gsk_gl_driver_end_frame (GskGLDriver *driver)
   driver->in_frame = FALSE;
 }
 
-void
+int
 gsk_gl_driver_collect_textures (GskGLDriver *driver)
 {
   GHashTableIter iter;
   gpointer value_p = NULL;
+  int old_size;
 
-  g_return_if_fail (GSK_IS_GL_DRIVER (driver));
-  g_return_if_fail (!driver->in_frame);
+  g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), 0);
+  g_return_val_if_fail (!driver->in_frame, 0);
+
+  old_size = g_hash_table_size (driver->textures);
 
   g_hash_table_iter_init (&iter, driver->textures);
   while (g_hash_table_iter_next (&iter, NULL, &value_p))
@@ -253,10 +260,41 @@ gsk_gl_driver_collect_textures (GskGLDriver *driver)
       Texture *t = value_p;
 
       if (t->in_use)
-        t->in_use = FALSE;
+        {
+          t->in_use = FALSE;
+          g_clear_pointer (&t->fbos, g_array_unref);
+        }
       else
         g_hash_table_iter_remove (&iter);
     }
+
+  return old_size - g_hash_table_size (driver->textures);
+}
+
+int
+gsk_gl_driver_collect_vaos (GskGLDriver *driver)
+{
+  GHashTableIter iter;
+  gpointer value_p = NULL;
+  int old_size;
+
+  g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), 0);
+  g_return_val_if_fail (!driver->in_frame, 0);
+
+  old_size = g_hash_table_size (driver->vaos);
+
+  g_hash_table_iter_init (&iter, driver->vaos);
+  while (g_hash_table_iter_next (&iter, NULL, &value_p))
+    {
+      Vao *v = value_p;
+
+      if (v->in_use)
+        v->in_use = FALSE;
+      else
+        g_hash_table_iter_remove (&iter);
+    }
+
+  return old_size - g_hash_table_size (driver->vaos);
 }
 
 static Texture *
@@ -328,6 +366,8 @@ gsk_gl_driver_create_texture (GskGLDriver *driver,
   t = find_texture_by_size (driver->textures, width, height);
   if (t != NULL && !t->in_use)
     {
+      GSK_NOTE (OPENGL, g_print ("Reusing Texture(%d) for size %dx%d\n",
+                                 t->texture_id, t->width, t->height));
       t->in_use = TRUE;
       return t->texture_id;
     }
@@ -346,6 +386,34 @@ gsk_gl_driver_create_texture (GskGLDriver *driver,
   return t->texture_id;
 }
 
+static Vao *
+find_vao (GHashTable    *vaos,
+          int            position_id,
+          int            uv_id,
+          int            n_quads,
+          GskQuadVertex *quads)
+{
+  GHashTableIter iter;
+  gpointer value_p = NULL;
+
+  g_hash_table_iter_init (&iter, vaos);
+  while (g_hash_table_iter_next (&iter, NULL, &value_p))
+    {
+      Vao *v = value_p;
+
+      if (v->position_id != position_id || v->uv_id != uv_id)
+        continue;
+
+      if (v->n_quads != n_quads)
+        continue;
+
+      if (memcmp (v->quads, quads, sizeof (GskQuadVertex) * n_quads) == 0)
+        return v;
+    }
+
+  return NULL;
+}
+
 int
 gsk_gl_driver_create_vao_for_quad (GskGLDriver   *driver,
                                    int            position_id,
@@ -360,6 +428,14 @@ gsk_gl_driver_create_vao_for_quad (GskGLDriver   *driver,
   g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), -1);
   g_return_val_if_fail (driver->in_frame, -1);
 
+  v = find_vao (driver->vaos, position_id, uv_id, n_quads, quads);
+  if (v != NULL && !v->in_use)
+    {
+      GSK_NOTE (OPENGL, g_print ("Reusing VAO(%d)\n", v->vao_id));
+      v->in_use = TRUE;
+      return v->vao_id;
+    }
+
   glGenVertexArrays (1, &vao_id);
   glBindVertexArray (vao_id);
 
@@ -385,6 +461,9 @@ gsk_gl_driver_create_vao_for_quad (GskGLDriver   *driver,
   v->buffer_id =  buffer_id;
   v->position_id = position_id;
   v->uv_id = uv_id;
+  v->n_quads = n_quads;
+  v->quads = g_memdup (quads, sizeof (GskQuadVertex) * n_quads);
+  v->in_use = TRUE;
   g_hash_table_insert (driver->vaos, GINT_TO_POINTER (vao_id), v);
 
 #ifdef G_ENABLE_DEBUG
index b69a387ca71db1503f1cc861874c73a2f0bb1794..f4836f5c562c0c63605304bd1ff4e8f1a4387394 100644 (file)
@@ -56,7 +56,8 @@ void            gsk_gl_driver_destroy_texture           (GskGLDriver     *driver
 void            gsk_gl_driver_destroy_vao               (GskGLDriver     *driver,
                                                          int              vao_id);
 
-void            gsk_gl_driver_collect_textures          (GskGLDriver     *driver);
+int             gsk_gl_driver_collect_textures          (GskGLDriver     *driver);
+int             gsk_gl_driver_collect_vaos              (GskGLDriver     *driver);
 
 G_END_DECLS
 
index 7d16ee1f12cd3deb547eac49cb193b4e61f2b301..ddc699099594635c2a3c43dc20d2ada117fe2020 100644 (file)
@@ -794,33 +794,24 @@ gsk_gl_renderer_validate_tree (GskGLRenderer *self,
   return TRUE;
 }
 
-static void
-render_item_clear (RenderItem    *item,
-                   GskGLRenderer *self)
-{
-  gsk_gl_driver_destroy_vao (self->gl_driver, item->render_data.vao_id);
-}
-
 static void
 gsk_gl_renderer_clear_tree (GskGLRenderer *self)
 {
-  int i;
+  int removed_textures, removed_vaos;
 
   if (self->gl_context == NULL)
     return;
 
   gdk_gl_context_make_current (self->gl_context);
 
-  for (i = 0; i < self->render_items->len; i++)
-    {
-      RenderItem *item = &g_array_index (self->render_items, RenderItem, i);
-
-      render_item_clear (item, self);
-    }
-
   g_clear_pointer (&self->render_items, g_array_unref);
 
-  gsk_gl_driver_collect_textures (self->gl_driver);
+  removed_textures = gsk_gl_driver_collect_textures (self->gl_driver);
+  removed_vaos = gsk_gl_driver_collect_vaos (self->gl_driver);
+
+  GSK_NOTE (OPENGL, g_print ("Collected: %d textures, %d vaos\n",
+                             removed_textures,
+                             removed_vaos));
 }
 
 static void